import { Api, JsonRpc } from 'eosjs';
import {JsSignatureProvider} from 'eosjs/dist/eosjs-jssig';


let NODE_ENDPOINT="http://47.97.231.205:8888";
let COMMENT_CONTRACT_NAME="user.comment";
let SHOP_CONTRACT_NAME="shop.info";
let USER_CONTRACT_NAME = "user.info";

// 权限名称
let user_permission = "active";

export class UserService {
    /*
    获取用户信息
    params:         user:       用户名
    returnType:     Promise
    PromiseValue:   字典类型，包含以下字段
                    rows: 用户信息对象或 null
     */
    static getUserInfo(user){
        return CommonService.readTable(USER_CONTRACT_NAME, USER_CONTRACT_NAME,
            USER_CONTRACT_NAME,{user: user},-1,-1).then(res=>{
            if(res.rows.length === 0){
                return {rows:null}
            }else{
                return {rows:res.rows[0]}
            }
        })
    }

    static getAllUserInfo(keysAndValue){
        return CommonService.readTable(USER_CONTRACT_NAME, USER_CONTRACT_NAME,
            USER_CONTRACT_NAME,keysAndValue,-1,-1).then(res=>{
            return getDataByPage(res.rows,{},-1,-1);
        }).catch(err => {
            return {rows:[]}
        })
    }

    /*
    修改当前用户的用户信息
    params:         user_name:      用户昵称
                    is_merchant：   是否是商家
                    avatar_url：     头像链接
                    phone_number:    手机号码
                    address：        地址
                    utils：          备用字段
    returnType:     Promise
    PromiseValue:   成功时：{status:true}
                    失败时：{status:false,error_info:string}
     */
    static updateUserInfo(user_name, is_merchant, avatar_url, phone_number, address, utils){
        return UserService.getUserInfo(CommonService.getCurrentUserName()).then(res=>{
            let dataValue ;
            let actionName ;
            if(res.rows){
                // 信息曾经被修改
                let is_merchant_val = res.rows.is_merchant !== 0;
                if(is_merchant !== is_merchant_val){
                    return {status:false,error_info:'is_merchant field can not be changed'}
                }
                actionName = "userupdate";
                dataValue = {user_name: user_name,is_merchant: is_merchant,
                    avatar_url: avatar_url,phone_number: phone_number,
                    address: address,utils: utils};
            }else{
                // 新的信息
                actionName = "userinsert";
                dataValue = {user_name: user_name,is_merchant: is_merchant,
                    avatar_url: avatar_url,phone_number: phone_number,
                    address: address,utils: utils};
            }
            return CommonService.invokeAction(USER_CONTRACT_NAME,user_permission,actionName,dataValue)
                .then(res => {
                    return {status:true};
                })
                .catch(err => {
                    return {status:false,error_info:err.toString()}
                });
        })
    }
}

export class CommentService {
    /*
    获取某个店铺的评论
    params:         shop_id:            店铺id
                    keysAndValues:      字典，查询条件 ，如{user:"bob"}查询bob用户的评论
                    page：              查询页号,小于等于0时不分页
                    size:               页的大小
    returnType:     Promise
    PromiseValue:   字典类型，包含以下字段
                    rows: 评论数组
                    page:（当使用分页时才有该字段）当前页号
                    total:（当使用分页时才有该字段）总页数
     */
    static getComments(shop_id, keysAndValues, page=-1, size=-1){
        return CommonService.readTable(COMMENT_CONTRACT_NAME, shop_id,
            "comments",keysAndValues,page,size)
    }

    /*
    获取所有评论
    params:         keysAndValues: 字典，查询条件 ，如{user:"bob"}查询bob用户的评论
                    page：查询页号,小于等于0时不分页
                    size:页的大小
    returnType:     Promise
    PromiseValue:   字典类型，包含以下字段
                    rows: 评论数组
                    page:（当使用分页时才有该字段）当前页号
                    total:（当使用分页时才有该字段）总页数
     */
    static getAllComments(keysAndValues, page=-1, size=-1){
        return ShopService.getShops({}, -1, -1).then(res =>{
                let promise_array = [];
                for(let i = 0 ; i < res.rows.length ; i++){
                    promise_array.push(CommonService.readTable(COMMENT_CONTRACT_NAME, res.rows[i].sid,
                        "comments",{},-1,-1).then(res =>{
                        return res.rows;
                    }))
                }
                return Promise.all(promise_array).then((resultList) => {
                    let all_comments = [];
                    for(let i = 0 ; i < resultList.length ; i++){
                        all_comments = all_comments.concat(resultList[i]);
                    }
                    return getDataByPage(all_comments, keysAndValues, page, size);
                })
            }
        )
    }

    /*
    发表评论
    params:         shop_id：店铺id
                    content: 评论内容
                    reply_id: 回复的哪一条评论的id，若为非回复评论该值为0
    returnType:     Promise
    PromiseValue:   成功时：{status:true}
                    失败时：{status:false,error_info:string}
     */
    static insertComment(shop_id, content, reply_id){
        return CommonService.invokeAction(COMMENT_CONTRACT_NAME,user_permission,"insert",
            {content:content, shopid:shop_id, replyid:reply_id})
            .then(res => {
                return {status:true};
            })
            .catch(err => {
                return {status:false,error_info:err.toString()}
            });
    }

    /*
    修改评论
    params:         shop_id：店铺id
                    cid：要修改的评论id
                    content: 评论内容
    returnType:     Promise
    PromiseValue:   成功时：{status:true}
                    失败时：{status:false,error_info:string}
     */
    static updateComment(shop_id, cid, content){
        return CommonService.invokeAction(COMMENT_CONTRACT_NAME,user_permission,"update",
            {cid: cid, content:content, shopid:shop_id})
        // {cid: cid, content:content, shopid:shop_id, visible: visible})

    .then(res => {
                return {status:true};
            })
            .catch(err => {
                return {status:false,error_info:err.toString()}
            });
    }

    /*
    删除评论
    params:         shop_id：店铺id
                    cid：要删除的评论id
    returnType:     Promise
    PromiseValue:   成功时：{status:true}
                    失败时：{status:false,error_info:string}
     */
    static eraseComment(shop_id, cid){
        return CommonService.invokeAction(COMMENT_CONTRACT_NAME,user_permission,"erase",
            {cid: cid, shopid:shop_id})
            .then(res => {
                return {status:true};
            })
            .catch(err => {
                return {status:false,error_info:err.toString()}
            });
    }
}

export class ShopService{
    /*
    获取店铺信息
    params:         keysAndValues: 字典，查询条件
                    page：查询页号,小于等于0时不分页
                    size:页的大小
    returnType:     Promise
    PromiseValue:   字典类型，包含以下字段
                    rows: 店铺信息数组
                    page:（当使用分页时才有该字段）当前页号
                    total:（当使用分页时才有该字段）总页数
     */
    static getShops(keysAndValues, page=1, size=20){
        return UserService.getAllUserInfo().then(res=>{
            let user_array = res.rows;
            let promise_array = [];
            for(let i = 0 ; i < user_array.length ; i++){
                promise_array.push(CommonService.readTable(SHOP_CONTRACT_NAME, user_array[i].user,
                    SHOP_CONTRACT_NAME, {}, -1, -1)
                    .then(res =>{
                        return res.rows;
                    })
                )
            }
            return Promise.all(promise_array).then((resultList) => {
                let all_shops = [];
                for(let i = 0 ; i < resultList.length ; i++){
                    all_shops = all_shops.concat(resultList[i]);
                }
                return getDataByPage(all_shops, keysAndValues, page, size);
            })
        });
    }

    /*
    当前用户添加店铺
    params:         shop_name:      店铺名称
                    picture_url:     图片链接
                    description：    店铺描述
                    tag:            店铺分类
                    address：        店铺地址
    returnType:     Promise
    PromiseValue:   成功时：{status:true}
                    失败时：{status:false,error_info:string}
     */
    static insertShop(shop_name, picture_url, description, tag, address){
        return ShopService.isUserAShopOwner(CommonService.getCurrentUserName()).then(res=>{
            if(res.rows){
                return CommonService.invokeAction(SHOP_CONTRACT_NAME,user_permission,"shopinsert",
                    {picture_url:picture_url, description:description,tag: tag, shop_name:shop_name, address:address})
                    .then(res => {
                        return {status:true};
                    })
                    .catch(err => {
                        return {status:false,error_info:err.toString()}
                    });
            }else{
                return {status: false,error_info: "current user is not a shop_owner"}
            }
        });

    }

    /*
    修改店铺信息
    params:         shop_id：        店铺id
                    shop_name:      修改后的店铺名称
                    description：    修改后的店铺描述
                    tag:            修改后的店铺分类
                    address:        修改后的店铺地址
    returnType:     Promise
    PromiseValue:   成功时：{status:true}
                    失败时：{status:false,error_info:string}
     */
    static updateShop(shop_id, shop_name, picture_url, description, tag, address){
        return ShopService.isUserAShopOwner(CommonService.getCurrentUserName()).then(res=>{
            if(res.rows){
                return CommonService.invokeAction(SHOP_CONTRACT_NAME,user_permission,"shopupdate",
                    {sid: shop_id, picture_url:picture_url, description: description, shop_name: shop_name,tag: tag,address: address})
                    .then(res => {
                        return {status:true};
                    })
                    .catch(err => {
                        return {status:false,error_info:err.toString()}
                    });
            }else{
                return {status: false,error_info: "current user is not a shop_owner"}
            }
        });
    }

    /*
    关闭店铺
    params:         shop_id：店铺id
    returnType:     Promise
    PromiseValue:   成功时：{status:true}
                    失败时：{status:false,error_info:string}
     */
    static eraseShop(shop_id){
        return ShopService.isUserAShopOwner(CommonService.getCurrentUserName()).then(res=>{
            if(res.rows){
                return CommonService.invokeAction(SHOP_CONTRACT_NAME,user_permission,"shoperase",
                    {sid: shop_id})
                    .then(res => {
                        return {status:true};
                    })
                    .catch(err => {
                        return {status:false,error_info:err.toString()}
                    });
            }else{
                return {status: false,error_info: "current user is not a shop_owner"}
            }
        });
    }

    /*
    管理员审核店铺申请
    params:         shop_id：店铺id
                    shop_owner: 店家用户名
                    is_checked: 是否通过审核，true或false
    returnType:     Promise
    PromiseValue:   成功时：{status:true}
                    失败时：{status:false,error_info:string}
     */
    static checkShop(shop_id, shop_owner, is_checked){
        return CommonService.invokeAction(SHOP_CONTRACT_NAME,user_permission,"shopcheck",
            {sid: shop_id, is_checked: is_checked, user: shop_owner})
            .then(res => {
                return {status:true};
            })
            .catch(err => {
                return {status:false,error_info:err.toString()}
            });
    }

    static isUserAShopOwner(user){
        return UserService.getUserInfo(user).then(res=>{
            let ans = {status:true};
            if(res.rows){
                ans.rows = Boolean(res.rows.is_merchant)
            }else {
                ans.rows = false
            }
            return ans
        }).catch(err => {
            return {status:true,rows:false}
        })
    }
}

export class ProductService {
    /*
    获取某一店铺的商品信息
    params:         shop_id :            店铺id
                    keysAndValues:       字典，查询条件
                    page：               查询页号,小于等于0时不分页
                    size:                页的大小
    returnType:     Promise
    PromiseValue:   字典类型，包含以下字段
                    rows: 商品数组
                    page:（当使用分页时才有该字段）当前页号
                    total:（当使用分页时才有该字段）总页数
     */
    static getProducts(shop_id, keysAndValues, page=1, size=20){
        return ShopService.getShops({sid: shop_id}, -1, -1).then(res =>{
            let shop_owners = res.rows;
            if(shop_owners.length === 0){
                return getDataByPage([], keysAndValues, page, size)
            }
            let shop_owner = shop_owners[0].user;
            if(!keysAndValues){
                keysAndValues = {shopid: shop_id}
            }
            else if(keysAndValues.hasOwnProperty("sid")){
                keysAndValues.shopid = keysAndValues.sid
            }
            if (!keysAndValues.hasOwnProperty("shopid")){
                keysAndValues.shopid = shop_id
            }
            return CommonService.readTable(SHOP_CONTRACT_NAME, shop_owner,
                "goods.info",keysAndValues,page,size)
        })
    }

    /*
    上架商品
    params:         shop_id：        店铺id
                    goods_name:      要上架的商品名称
                    description:     商品描述
                    picture_url:    图片url
    returnType:     Promise
    PromiseValue:   成功时：{status:true}
                    失败时：{status:false,error_info:string}
     */
    static insertProduct(shop_id, goods_name, description, picture_url){
        return ShopService.isUserAShopOwner(CommonService.getCurrentUserName()).then(res=>{
            if(res.rows){
                return CommonService.invokeAction(SHOP_CONTRACT_NAME,user_permission,"goodsinsert",
                    {shopid: shop_id, goods_name: goods_name, description: description, picture_url: picture_url})
                    .then(res => {
                        return {status:true};
                    })
                    .catch(err => {
                        return {status:false,error_info:err.toString()}
                    });
            }else{
                return {status: false,error_info: "current user is not a shop_owner"}
            }
        });
    }

    /*
    修改商品信息
    params:         shop_id：        店铺id
                    goods_id         商品id
                    goods_name       修改后的商品名称
                    description：    修改后的商品描述
                    picture_url:    图片url
    returnType:     Promise
    PromiseValue:   成功时：{status:true}
                    失败时：{status:false,error_info:string}
     */
    static updateProduct(shop_id, goods_id, goods_name, description, picture_url){
        return ShopService.isUserAShopOwner(CommonService.getCurrentUserName()).then(res=>{
            if(res.rows){
                return CommonService.invokeAction(SHOP_CONTRACT_NAME,user_permission,"goodsupdate",
                    {shopid: shop_id,gid: goods_id, goods_name: goods_name, description: description, picture_url: picture_url})
                    .then(res => {
                        return {status:true};
                    })
                    .catch(err => {
                        return {status:false,error_info:err.toString()}
                    });
            }else{
                return {status: false,error_info: "current user is not a shop_owner"}
            }
        });
    }

    /*
    下架商品
    params:         shop_id：店铺id
                    goods_id: 下架的商品id
    returnType:     Promise
    PromiseValue:   成功时：{status:true}
                    失败时：{status:false,error_info:string}
     */
    static eraseProduct(shop_id, goods_id){
        return ShopService.isUserAShopOwner(CommonService.getCurrentUserName()).then(res=>{
            if(res.rows){
                return CommonService.invokeAction(SHOP_CONTRACT_NAME,user_permission,"goodserase",
                    {shopid: shop_id,gid: goods_id})
                    .then(res => {
                        return {status:true};
                    })
                    .catch(err => {
                        return {status:false,error_info:err.toString()}
                    });
            }else{
                return {status: false,error_info: "current user is not a shop_owner"}
            }
        });
    }
}

export class CommonService{
    /*
    登陆
    params:         username：用户名
                    private_key: 私钥
    returnType:     Promise
    PromiseValue:   成功时：{status:true，rows:[user,shop_owner,admin],info:true/false}
                            rows记录了用户拥有的所有权限,
                            user:普通用户 ; shop_owner:商家 ; admin:管理员
                            info为false时表示用户信息未曾填写
                    失败时：{status:false,error_info:string}
     */
    static login(username, private_key){
        // localStorage.setItem('name_account', username);
        // localStorage.setItem('private_key', private_key);
        return invokeAction(COMMENT_CONTRACT_NAME, user_permission, 'login', username, private_key, { user: username })
            .then(res => {
                let ans = {status:true, rows:[], info:true};
                if(username === 'admin'){
                    ans.rows.push('admin')
                }
                if(res.rows){
                    if(res.rows.is_merchant){
                        ans.rows.push('shop_owner');
                    }
                }else{
                    ans.info = false;
                }
                ans.rows.push('user');
                return ans
            })
            .catch(err => {
                // console.error("登录失败")
                // localStorage.removeItem('name_account');
                // localStorage.removeItem('private_key');
                return {status:false,error_info:err.toString()}
            });
    }

    /*
    注销
     */
    static logout(){
        localStorage.removeItem('name_account');
        localStorage.removeItem('private_key');
    }

    static getCurrentUserName(){
        let name = localStorage.getItem('name_account');
        return name ? name : "";
    }

    static readTable(code, scope, tableName, keysAndValues, page=-1, size=-1){
        return readTable(code, scope, tableName).then(res =>{
            let array = res.rows;
            return getDataByPage(array, keysAndValues, page, size);
        });
    }

    static invokeAction(contract, permission, action, dataValue){
        let user = localStorage.getItem('name_account');
        let key = localStorage.getItem('private_key');
        if(!dataValue.hasOwnProperty("user")){
            dataValue.user = user;
        }
        return invokeAction(contract, permission, action, user, key, dataValue)
    }
}

function getDataByPage(array, keysAndValues, page=-1, size=-1) {
    let ans = {rows:[]};
    for(let i = 0 ;i < array.length ;i++){
        let item = array[i];
        let match = true;
        for (let key in keysAndValues) {
            let value = keysAndValues[key];
            if(item.hasOwnProperty(key) && item[key] !== value){
                match = false;
                break;
            }
        }
        if(match){
            ans.rows.push(item)
        }
    }
    if(page > 0 && size > 0){
        ans.page = page;
        ans.total = Math.ceil(ans.rows.length / size);
        ans.rows = ans.rows.slice((page - 1) * size, page * size)
    }
    return ans;
}

async function invokeAction(contract, permission, action, name_account, private_key, dataValue) {
    const rpc = new JsonRpc(NODE_ENDPOINT);
    const signatureProvider = new JsSignatureProvider([private_key]);
    const api = new Api({
        rpc,
        signatureProvider,
        textDecoder: new TextDecoder(),
        textEncoder: new TextEncoder()
    });
    try {
        const resultWithConfig = await api.transact(
            {
                actions: [
                    {
                        account: contract,
                        name: action,
                        authorization: [
                            {
                                actor: name_account,
                                permission: permission
                            }
                        ],
                        data: dataValue
                    }
                ]
            },
            {
                blocksBehind: 3,
                expireSeconds: 30
            }
        );
        return resultWithConfig;
    } catch (err) {
        throw err;
    }
}

async function readTable(code, scope, tableName, index, value) {
    try {
        let jsonRequestValue = {
            json: true,              // Get the response as json
            code: code,     // Contract that we target
            scope: scope,         // Account that owns the data
            table: tableName,        // Table name
            reverse : false,            // Optional: Get reversed data
            show_payer : false,         // Optional: Show ram payer
            limit : -1
        };
        if(index && value){
            jsonRequestValue.table_key = index;
            jsonRequestValue.lower_bound = value
        }
        const { JsonRpc } = require('eosjs');
        const fetch = require('node-fetch');
        const rpc = new JsonRpc(NODE_ENDPOINT, { fetch });
        return await rpc.get_table_rows(jsonRequestValue)
    } catch (err) {
        throw err;
    }
}
